import { Detector } from "./detector/Detector";
import { GeometryType } from "../geometry/GeometryType";
import { GjkEpaDetector } from "./detector/GjkEpaDetector";
import { SphereSphereDetector } from "./detector/SphereSphereDetector";
import { SphereBoxDetector } from "./detector/SphereBoxDetector";
import { SphereCapsuleDetector } from "./detector/SphereCapsuleDetector";
import { BoxBoxDetector } from "./detector/BoxBoxDetector";
import { CapsuleCapsuleDetector } from "./detector/CapsuleCapsuleDetector";

/**
 * CollisionMatrix provides corresponding collision detector for a pair of
 * two geometries of given types.
 */
export class CollisionMatrix {
	detectors: Array<Array<Detector>>;


	constructor() {
		this.detectors = new Array<Array<Detector>>(8);
		for (let i = 0; i < 6; ++i) {
			this.detectors[i] = new Array<Detector>(8);
		}

		var gjkEpaDetector: GjkEpaDetector = new GjkEpaDetector();

		var sp: number = GeometryType._SPHERE;
		var bo: number = GeometryType._BOX;
		var cy: number = GeometryType._CYLINDER;
		var co: number = GeometryType._CONE;
		var ca: number = GeometryType._CAPSULE;
		var ch: number = GeometryType._CONVEX_HULL;

		this.detectors[sp][sp] = new SphereSphereDetector();
		this.detectors[sp][bo] = new SphereBoxDetector(false);
		this.detectors[sp][cy] = gjkEpaDetector;
		this.detectors[sp][co] = gjkEpaDetector;
		this.detectors[sp][ca] = new SphereCapsuleDetector(false);
		this.detectors[sp][ch] = gjkEpaDetector;

		this.detectors[bo][sp] = new SphereBoxDetector(true);
		this.detectors[bo][bo] = new BoxBoxDetector();
		this.detectors[bo][cy] = gjkEpaDetector;
		this.detectors[bo][co] = gjkEpaDetector;
		this.detectors[bo][ca] = gjkEpaDetector;
		this.detectors[bo][ch] = gjkEpaDetector;

		this.detectors[cy][sp] = gjkEpaDetector;
		this.detectors[cy][bo] = gjkEpaDetector;
		this.detectors[cy][cy] = gjkEpaDetector;
		this.detectors[cy][co] = gjkEpaDetector;
		this.detectors[cy][ca] = gjkEpaDetector;
		this.detectors[cy][ch] = gjkEpaDetector;

		this.detectors[co][sp] = gjkEpaDetector;
		this.detectors[co][bo] = gjkEpaDetector;
		this.detectors[co][cy] = gjkEpaDetector;
		this.detectors[co][co] = gjkEpaDetector;
		this.detectors[co][ca] = gjkEpaDetector;
		this.detectors[co][ch] = gjkEpaDetector;

		this.detectors[ca][sp] = new SphereCapsuleDetector(true);
		this.detectors[ca][bo] = gjkEpaDetector;
		this.detectors[ca][cy] = gjkEpaDetector;
		this.detectors[ca][co] = gjkEpaDetector;
		this.detectors[ca][ca] = new CapsuleCapsuleDetector();
		this.detectors[ca][ch] = gjkEpaDetector;

		this.detectors[ch][sp] = gjkEpaDetector;
		this.detectors[ch][bo] = gjkEpaDetector;
		this.detectors[ch][cy] = gjkEpaDetector;
		this.detectors[ch][co] = gjkEpaDetector;
		this.detectors[ch][ca] = gjkEpaDetector;
		this.detectors[ch][ch] = gjkEpaDetector;
	}

	// --- public ---

	/**
	 * Returns an appropriate collision detector of two geometries of types `geomType1` and `geomType2`.
	 *
	 * This method is **not symmetric**, so `getDetector(a, b)` may not be equal to `getDetector(b, a)`.
	 */
	public getDetector(geomType1: number, geomType2: number): Detector {
		return this.detectors[geomType1][geomType2];
	}
}
